﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;

namespace RayDen.Library.Core.Primitives
{
    public static class SPD_Data
    {

        #region Illumination

        public static double[] A = new[] {
            380.000000 ,1.870000 ,
            385.000000 ,2.360000 ,
            390.000000 ,2.940000 ,
            395.000000 ,3.470000 ,
            400.000000 ,5.170000 ,
            405.000000 ,19.490000,
            410.000000 ,6.130000 ,
            415.000000 ,6.240000 ,
            420.000000 ,7.010000 ,
            425.000000 ,7.790000 ,
            430.000000 ,8.560000 ,
            435.000000 ,43.669998,
            440.000000 ,16.940001,
            445.000000 ,10.720000,
            450.000000 ,11.350000,
            455.000000 ,11.890000,
            460.000000 ,12.370000,
            465.000000 ,12.750000,
            470.000000 ,13.000000,
            475.000000 ,13.150000,
            480.000000 ,13.230000,
            485.000000 ,13.170000,
            490.000000 ,13.130000,
            495.000000 ,12.850000,
            500.000000 ,12.520000,
            505.000000 ,12.200000,
            510.000000 ,11.830000,
            515.000000 ,11.500000,
            520.000000 ,11.220000,
            525.000000 ,11.050000,
            530.000000 ,11.030000,
            535.000000 ,11.180000,
            540.000000 ,11.530000,
            545.000000 ,27.740000,
            550.000000 ,17.049999,
            555.000000 ,13.550000,
            560.000000 ,14.330000,
            565.000000 ,15.010000,
            570.000000 ,15.520000,
            575.000000 ,18.290001,
            580.000000 ,19.549999,
            585.000000 ,15.480000,
            590.000000 ,14.910000,
            595.000000 ,14.150000,
            600.000000 ,13.220000,
            605.000000 ,12.190000,
            610.000000 ,11.120000,
            615.000000 ,10.030000,
            620.000000 ,8.950000,
            625.000000 ,7.960000,
            630.000000 ,7.020000,
            635.000000 ,6.200000,
            640.000000 ,5.420000,
            645.000000 ,4.730000,
            650.000000 ,4.150000,
            655.000000 ,3.640000,
            660.000000 ,3.200000,
            665.000000 ,2.810000,
            670.000000 ,2.470000,
            675.000000 ,2.180000,
            680.000000 ,1.930000,
            685.000000 ,1.720000,
            690.000000 ,1.670000,
            695.000000 ,1.430000,
            700.000000 ,1.290000,
            705.000000 ,1.190000,
            710.000000 ,1.080000,
            715.000000 ,0.960000,
            720.000000 ,0.880000,
            725.000000 ,0.810000,
            730.000000 ,0.770000,
            735.000000 ,0.750000,
            740.000000 ,0.730000,
            745.000000 ,0.680000,
            750.000000 ,0.690000,
            755.000000 ,0.640000,
            760.000000 ,0.680000,
            765.000000 ,0.690000,
            770.000000 ,0.610000,
            775.000000 ,0.520000,
            780.000000 ,0.430000 
                    };

        public static double[] D6500 = new[] {
            300.000000 ,0.034100 ,
            305.000000 ,1.664300 ,
            310.000000 ,3.294500 ,
            315.000000 ,11.765200,
            320.000000 ,20.236000,
            325.000000 ,28.644699,
            330.000000 ,37.053501,
            335.000000 ,38.501099,
            340.000000 ,39.948799,
            345.000000 ,42.430199,
            350.000000 ,44.911701,
            355.000000 ,45.775002,
            360.000000 ,46.638302,
            365.000000 ,49.363701,
            370.000000 ,52.089100,
            375.000000 ,51.032299,
            380.000000 ,49.975498,
            385.000000 ,52.311798,
            390.000000 ,54.648201,
            395.000000 ,68.701500,
            400.000000 ,82.754898,
            405.000000 ,87.120399,
            410.000000 ,91.486000,
            415.000000 ,92.458900,
            420.000000 ,93.431801,
            425.000000 ,90.056999,
            430.000000 ,86.682297,
            435.000000 ,95.773598,
            440.000000 ,104.864998,
            445.000000 ,110.935997,
            450.000000 ,117.008003,
            455.000000 ,117.410004,
            460.000000 ,117.811996,
            465.000000 ,116.335999,
            470.000000 ,114.861000,
            475.000000 ,115.391998,
            480.000000 ,115.922997,
            485.000000 ,112.366997,
            490.000000 ,108.810997,
            495.000000 ,109.082001,
            500.000000 ,109.353996,
            505.000000 ,108.578003,
            510.000000 ,107.802002,
            515.000000 ,106.295998,
            520.000000 ,104.790001,
            525.000000 ,106.238998,
            530.000000 ,107.689003,
            535.000000 ,106.046997,
            540.000000 ,104.404999,
            545.000000 ,104.224998,
            550.000000 ,104.045998,
            555.000000 ,102.023003,
            560.000000 ,100.000000,
            565.000000 ,98.167099 ,
            570.000000 ,96.334198 ,
            575.000000 ,96.061096 ,
            580.000000 ,95.788002 ,
            585.000000 ,92.236801 ,
            590.000000 ,88.685600 ,
            595.000000 ,89.345901 ,
            600.000000 ,90.006203 ,
            605.000000 ,89.802597 ,
            610.000000 ,89.599098 ,
            615.000000 ,88.648903 ,
            620.000000 ,87.698700 ,
            625.000000 ,85.493599 ,
            630.000000 ,83.288597 ,
            635.000000 ,83.493896 ,
            640.000000 ,83.699203 ,
            645.000000 ,81.862999 ,
            650.000000 ,80.026802 ,
            655.000000 ,80.120697 ,
            660.000000 ,80.214600 ,
            665.000000 ,81.246201 ,
            670.000000 ,82.277802 ,
            675.000000 ,80.280998 ,
            680.000000 ,78.284203 ,
            685.000000 ,74.002701 ,
            690.000000 ,69.721298 ,
            695.000000 ,70.665199 ,
            700.000000 ,71.609100 ,
            705.000000 ,72.978996 ,
            710.000000 ,74.348999 ,
            715.000000 ,67.976501 ,
            720.000000 ,61.604000 ,
            725.000000 ,65.744797 ,
            730.000000 ,69.885597 ,
            735.000000 ,72.486298 ,
            740.000000 ,75.086998 ,
            745.000000 ,69.339798 ,
            750.000000 ,63.592701 ,
            755.000000 ,55.005402 ,
            760.000000 ,46.418201 ,
            765.000000 ,56.611801 ,
            770.000000 ,66.805397 ,
            775.000000 ,65.094101 ,
            780.000000 ,63.382801 ,
            785.000000 ,63.843399 ,
            790.000000 ,64.304001 ,
            795.000000 ,61.877899 ,
            800.000000 ,59.451900 ,
            805.000000 ,55.705399 ,
            810.000000 ,51.959000 ,
            815.000000 ,54.699799 ,
            820.000000 ,57.440601 ,
            825.000000 ,58.876499 ,
            830.000000 ,60.312500
        };



        public static double[] D5000 = new[] {
            300.000000f, 0.019200,
            305.000000f, 1.036600,
            310.000000f, 2.054000,
            315.000000f, 4.913000,
            320.000000f, 7.772000,
            325.000000f, 11.255700,
            330.000000f, 14.739500,
            335.000000f, 16.339001,
            340.000000f, 17.938601,
            345.000000f, 19.466700,
            350.000000f, 20.994900,
            355.000000f, 22.459999,
            360.000000f, 23.925100,
            365.000000f, 25.433901,
            370.000000f, 26.942699,
            375.000000f, 25.701799,
            380.000000f, 24.461000,
            385.000000f, 27.150700,
            390.000000f, 29.840401,
            395.000000f, 39.550301,
            400.000000f, 49.664001,
            405.000000f, 53.155998,
            410.000000f, 56.647999,
            415.000000f, 58.445999,
            420.000000f, 60.243999,
            425.000000f, 59.230000,
            430.000000f, 58.216000,
            435.000000f, 66.973999,
            440.000000f, 75.732002,
            445.000000f, 81.998001,
            450.000000f, 88.264000,
            455.000000f, 89.930000,
            460.000000f, 91.596001,
            465.000000f, 91.940002,
            470.000000f, 92.283997,
            475.000000f, 94.155998,
            480.000000f, 96.028000,
            485.000000f, 94.311996,
            490.000000f, 92.596001,
            495.000000f, 94.424004,
            500.000000f, 96.251999,
            505.000000f, 96.662003f,
            510.000000f, 97.071999f,
            515.000000f, 97.314003f,
            520.000000f, 97.556000f,
            525.000000f, 100.005997f,
            530.000000f, 102.456001f,
            535.000000f, 101.694000f,
            540.000000f, 100.931999f,
            545.000000f, 101.678001f,
            550.000000f, 102.424004f,
            555.000000f, 101.211998f,
            560.000000f, 100.000000f,
            565.000000f, 98.036697f,
            570.000000f, 96.073402f,
            575.000000f, 95.678398f,
            580.000000f, 95.283501f,
            585.000000f, 92.577103f,
            590.000000f, 89.870697f,
            595.000000f, 90.772499f,
            600.000000f, 91.674400f,
            605.000000f, 91.739502f,
            610.000000f, 91.804703f,
            615.000000f, 90.964798f,
            620.000000f, 90.124901f,
            625.000000f, 87.998299f,
            630.000000f, 85.871696f,
            635.000000f, 86.715302f,
            640.000000f, 87.558899f,
            645.000000f, 86.069000f,
            650.000000f, 84.579102f,
            655.000000f, 85.167603f,
            660.000000f, 85.756203f,
            665.000000f, 87.126404f,
            670.000000f, 88.496597f,
            675.000000f, 86.769997f,
            680.000000f, 85.043404f,
            685.000000f, 79.994698f,
            690.000000f, 74.946098f,
            695.000000f, 76.384598f,
            700.000000f, 77.823196f,
            705.000000f, 78.671303f,
            710.000000f, 79.519501f,
            715.000000f, 72.694199f,
            720.000000f, 65.869003f,
            725.000000f, 70.179100f,
            730.000000f, 74.489197f,
            735.000000f, 77.212601f,
            740.000000f, 79.935997f,
            745.000000f, 73.797401f,
            750.000000f, 67.658897f,
            755.000000f, 58.633598f,
            760.000000f, 49.608398f,
            765.000000f, 60.462101f,
            770.000000f, 71.315804f,
            775.000000f, 69.405701f,
            780.000000f, 67.495598f,
            785.000000f, 68.032303f,
            790.000000f, 68.569000f,
            795.000000f, 65.958900f,
            800.000000f, 63.348801f,
            805.000000f, 59.333599f,
            810.000000f, 55.318501f,
            815.000000f, 58.228600f,
            820.000000f, 61.138699f,
            825.000000f, 62.712101f,
            830.000000f, 64.285500f
        };

        #endregion


        #region Reflection

        public static double[] Al_k = new[] {
                //298.757050 ,3.593750,
                //302.400421 ,3.640000,
                //306.133759 ,3.689375,
                //309.960449 ,3.740000,
                //313.884003 ,3.789375,
                //317.908142 ,3.840000,
                //322.036835 ,3.894375,
                //326.274139 ,3.950000,
                //330.624481 ,4.005000,
                //335.092377 ,4.060000,
                //339.682678 ,4.113750,
                //344.400482 ,4.170000,
                //349.251221 ,4.233750,
                //354.240509 ,4.300000,
                //359.374420 ,4.365000,
                364.659332 ,4.430000,
                370.102020 ,4.493750,
                375.709625 ,4.560000,
                381.489777 ,4.633750,
                387.450562 ,4.710000,
                393.600555 ,4.784375,
                399.948975 ,4.860000,
                406.505493 ,4.938125,
                413.280579 ,5.020000,
                420.285339 ,5.108750,
                427.531647 ,5.200000,
                435.032196 ,5.290000,
                442.800629 ,5.380000,
                450.851562 ,5.480000,
                459.200653 ,5.580000,
                467.864838 ,5.690000,
                476.862213 ,5.800000,
                486.212463 ,5.915000,
                495.936707 ,6.030000,
                506.057861 ,6.150000,
                516.600769 ,6.280000,
                527.592224 ,6.420000,
                539.061646 ,6.550000,
                551.040771 ,6.700000,
                563.564453 ,6.850000,
                576.670593 ,7.000000,
                590.400818 ,7.150000,
                604.800842 ,7.310000,
                619.920898 ,7.480000,
                635.816284 ,7.650000,
                652.548279 ,7.820000,
                670.184753 ,8.010000,
                688.800964 ,8.210000,
                708.481018 ,8.390000,
                729.318665 ,8.570000,
                751.419250 ,8.620000,
                774.901123 ,8.600000,
                799.897949 ,8.450000,
                826.561157 ,8.310000,
                855.063293 ,8.210000,
                885.601257 ,8.210000 
                        };

        public static double[] MacBeth1 = new double[] {

            380, 0.048,
            385, 0.051,
            390, 0.055,
            395, 0.06,
            400, 0.065,
            405, 0.068,
            410, 0.068,
            415, 0.067,
            420, 0.064,
            425, 0.062,
            430, 0.059,
            435, 0.057,
            440, 0.055,
            445, 0.054,
            450, 0.053,
            455, 0.053,
            460, 0.052,
            465, 0.052,
            470, 0.052,
            475, 0.053,
            480, 0.054,
            485, 0.055,
            490, 0.057,
            495, 0.059,
            500, 0.061,
            505, 0.062,
            510, 0.065,
            515, 0.067,
            520, 0.07,
            525, 0.072,
            530, 0.074,
            535, 0.075,
            540, 0.076,
            545, 0.078,
            550, 0.079,
            555, 0.082,
            560, 0.087,
            565, 0.092,
            570, 0.1,
            575, 0.107,
            580, 0.115,
            585, 0.122,
            590, 0.129,
            595, 0.134,
            600, 0.138,
            605, 0.142,
            610, 0.146,
            615, 0.15,
            620, 0.154,
            625, 0.158,
            630, 0.163,
            635, 0.167,
            640, 0.173,
            645, 0.18,
            650, 0.188,
            655, 0.196,
            660, 0.204,
            665, 0.213,
            670, 0.222,
            675, 0.231,
            680, 0.242,
            685, 0.251,
            690, 0.261,
            695, 0.271,
            700, 0.282,
            705, 0.294,
            710, 0.305,
            715, 0.318,
            720, 0.334,
            725, 0.354,
            730, 0.372,
            735, 0.392,
            740, 0.409,
            745, 0.42,
            750, 0.436,
            755, 0.45,
            760, 0.462,
            765, 0.465,
            770, 0.448,
            775, 0.432,
            780, 0.421
        };

        #endregion


        public static RgbSpectrum Convert(ref SampledSpectrum ss)
        {
            return ss.ToRgb();
        }

        public static SampledSpectrum Convert(ref RgbSpectrum s, SpectrumType t)
        {
            return new SampledSpectrum(ref s, t);
        }

        public static SampledSpectrum FromSampled(double[] data, SpectrumType t)
        {
            var vals = data.ToList().Where((c, i) => i % 2 != 0).Select(l => (float)l).ToArray();
            var lambdas = data.ToList().Where((c, i) => i % 2 == 0).Select(l => (float)l).ToArray();
            var s = SampledSpectrum.FromSampled(lambdas, vals, t);
            return s;
        }
        public static RegularSPD RegularSpdFromSampled(double[] data, SpectrumType t)
        {
            var vals = data.ToList().Where((c, i) => i % 2 != 0).Select(l => (float)l).ToArray();
            var lambdas = data.ToList().Where((c, i) => i % 2 == 0).Select(l => (float)l).ToArray();
            return new RegularSPD(vals, lambdas.Min(), lambdas.Max(), lambdas.Length);
        }

        public static IrregularSPD IrregularFromSampled(double[] data, SpectrumType t)
        {
            var vals = data.ToList().Where((c, i) => i % 2 != 0).Select(l => (float)l).ToArray();
            var lambdas = data.ToList().Where((c, i) => i % 2 == 0).Select(l => (float)l).ToArray();
            return new IrregularSPD(lambdas, vals, lambdas.Length);
        }
        public static double[] FromFile(string spdFile)
        {
            var result = new List<double>();
            if (!File.Exists(spdFile))
            {
                throw new ApplicationException("File not found");
            }
            
            foreach (var str in File.ReadAllLines(spdFile))
            {
                if (str.Contains("#") || string.IsNullOrWhiteSpace(str))
                {
                    continue;
                }
                var ds = str.Split(' ', ',', '\t').Where(s=>!String.IsNullOrWhiteSpace(s)).ToArray();
                result.Add(double.Parse(ds[0],  NumberStyles.Any ,CultureInfo.InvariantCulture));
                result.Add(double.Parse(ds[1], NumberStyles.Any, CultureInfo.InvariantCulture));
            }
            return result.ToArray();
        }

        public static double[] FromFile(string spdFile, double m)
        {
            var result = new List<double>();
            if (!File.Exists(spdFile))
            {
                throw new ApplicationException("File not found");
            }

            foreach (var str in File.ReadAllLines(spdFile))
            {
                if (str.Contains("#") || string.IsNullOrWhiteSpace(str))
                {
                    continue;
                }
                var ds = str.Split(' ', ',', '\t').Where(s => !String.IsNullOrWhiteSpace(s)).ToArray();
                result.Add(double.Parse(ds[0], NumberStyles.Any, CultureInfo.InvariantCulture) * m);
                result.Add(double.Parse(ds[1], NumberStyles.Any, CultureInfo.InvariantCulture));
            }
            return result.ToArray();
        }
    }


    public static class Sun_SPD_Data
    {

        public static float[] sun_k_oWavelengths = new float[]  {
                                                                300, 305, 310, 315, 320,
                                                                325, 330, 335, 340, 345,
                                                                350, 355,

                                                                445, 450, 455, 460, 465,
                                                                470, 475, 480, 485, 490,
                                                                495,

                                                                500, 505, 510, 515, 520,
                                                                525, 530, 535, 540, 545,
                                                                550, 555, 560, 565, 570,
                                                                575, 580, 585, 590, 595,

                                                                600, 605, 610, 620, 630,
                                                                640, 650, 660, 670, 680,
                                                                690,

                                                                700, 710, 720, 730, 740,
                                                                750, 760, 770, 780, 790
                                                                };

        public static double[] sun_k_oAmplitudes = new[] {
                                                                  10.0,
                                                                  4.8,
                                                                  2.7,
                                                                  1.35,
                                                                  .8,
                                                                  .380,
                                                                  .160,
                                                                  .075,
                                                                  .04,
                                                                  .019,
                                                                  .007,
                                                                  .0,
  
                                                                  .003,
                                                                  .003,
                                                                  .004,
                                                                  .006,
                                                                  .008,
                                                                  .009,
                                                                  .012,
                                                                  .014,
                                                                  .017,
                                                                  .021,
                                                                  .025,

                                                                  .03,
                                                                  .035,
                                                                  .04,
                                                                  .045,
                                                                  .048,
                                                                  .057,
                                                                  .063,
                                                                  .07,
                                                                  .075,
                                                                  .08,
                                                                  .085,
                                                                  .095,
                                                                  .103,
                                                                  .110,
                                                                  .12,
                                                                  .122,
                                                                  .12,
                                                                  .118,
                                                                  .115,
                                                                  .12,

                                                                  .125,
                                                                  .130,
                                                                  .12,
                                                                  .105,
                                                                  .09,
                                                                  .079,
                                                                  .067,
                                                                  .057,
                                                                  .048,
                                                                  .036,
                                                                  .028,
  
                                                                  .023,
                                                                  .018,
                                                                  .014,
                                                                  .011,
                                                                  .010,
                                                                  .009,
                                                                  .007,
                                                                  .004,
                                                                  .0,
                                                                  .0
                                                                };



        public static float[] sun_k_gWavelengths = new float[] {
                                                                759,
                                                                760,
                                                                770,
                                                                771
                                                            };

        public static float[] sun_k_gAmplitudes = new float[] {
                                                              0.0f,
                                                              3.0f,
                                                              0.210f,
                                                              0.0f
                                                            };

        // k_wa Spectrum table from pg 130, MI.
        public static float[] sun_k_waWavelengths = new float[] {
                                                          689,
                                                          690,
                                                          700,
                                                          710,
                                                          720,
                                                          730,
                                                          740,
                                                          750,
                                                          760,
                                                          770,
                                                          780,
                                                          790,
                                                          800
                                                        };

        public static double[] sun_k_waAmplitudes = new double[] {
                                                      0,
                                                      0.160e-1,
                                                      0.240e-1,
                                                      0.125e-1,
                                                      0.100e+1,
                                                      0.870,
                                                      0.610e-1,
                                                      0.100e-2,
                                                      0.100e-4,
                                                      0.100e-4,
                                                      0.600e-3,
                                                      0.175e-1,
                                                      0.360e-1
                                                    };

        // Sun radiance in range 380-750 nm by 10nm in W.m-2.sr-1.nm-1
        public static float[] sun_solAmplitudes = new float[]{
                                                    16559.0f, 16233.7f, 21127.5f, 25888.2f, 25829.1f,
                                                    24232.3f, 26760.5f, 29658.3f, 30545.4f, 30057.5f,
                                                    30663.7f, 28830.4f, 28712.1f, 27825.0f, 27100.6f,
                                                    27233.6f, 26361.3f, 25503.8f, 25060.2f, 25311.6f,
                                                    25355.9f, 25134.2f, 24631.5f, 24173.2f, 23685.3f,
                                                    23212.1f, 22827.7f, 22339.8f, 21970.2f, 21526.7f,
                                                    21097.9f, 20728.3f, 20240.4f, 19870.8f, 19427.2f,
                                                    19072.4f, 18628.9f, 18259.2f
                                                };

    }
}
